<?php
require_once FORAGE_APP_PATH . '/engine/EngineModifiable.php';
require_once FORAGE_APP_PATH . '/engine/EngineSearchable.php';
/**
 * This is the base class for all engine interfacing classes
 *
 * @author Rob Young <rob@roryoung.co.uk>
 * @package forage.engine
 */
abstract class ForageEngine {
  /**
   * Registered ForageEngineBehaviour objects
   *
   * @var array
   */
  protected $behaviours;

  /**
   * Create a new concrete instance of a ForageEngine.
   *
   * @param string $dsn data source name
   * @param array config
   * @return ForageEngine
   */
  public static function create($dsn, $config)
  {
    $parts = explode(':', $dsn, 2);
    $type  = $parts[0];
    $dsn   = isset($parts[1]) ? $parts[1] : '';
    $type  = strtolower($type);
    $file  = ucfirst($type) . 'Engine';
    $class = 'Forage' . $file;
    if (!class_exists($class)) {
      $path  = FORAGE_APP_PATH . '/engine/' . $type . '/' . $file . '.php';
      if (!file_exists($path)) {
        throw new ForageEngineException("Engine does not exist " . $type);
      }
      require_once $path;
      if (!class_exists($class)) {
        throw new ForageEngineException("Engine does not exist " . $type);
      }
    }
    $engine = new $class();
    if (!($engine instanceof ForageEngine)) {
      throw new ForageEngineException("Invalid engine " . $type);
    }
    $engine->initialize($dsn, $config);
    
    return $engine;
  }

  /**
   * Class constructor
   * Set the ForageEngineBehaviourHandler
   */
  public function __construct()
  {
    $this->behaviours = new ForageEngineBehaviourHandler();
  }

  /**
   * Called on a newly created ForageEngine to set it up.
   *
   * @param string $dsn data source name
   * @param array $config
   */
  public abstract function initialize($dsn, $config);

  /**
   * Return a concrete ForageQuery object to be used for searching.
   * This method can be overriden to provide specific ForageQuery
   * implementations.
   *
   * @return ForageQuery
   */
  public function getQuery()
  {
    return new ForageQuery();
  }

  public function addBehaviour($behaviour)
  {
    $behaviour->setEngine($this);
    $this->behaviours->addBehaviour($behaviour);
  }

  /**
   * Magic function call method
   * Passes all unhandled calls on to the ForageEngineBehaviourHandler
   *
   * @param string $method
   * @param array $args
   * @return mixed
   */
  public function __call($method, $args)
  {
    return $this->behaviours->__call($method, $args);
  }
}

/**
 * Exceptions relating to underlying engines.
 */
class ForageEngineException extends ForageException {}
